package com.haredot.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.haredot.dto.BindSysMenuDto;
import com.haredot.entity.Sys;
import com.haredot.exception.ServiceAccessException;
import com.haredot.mapper.MenuMapper;
import com.haredot.mapper.SysMapper;
import com.haredot.service.SystemService;
import com.haredot.vo.R;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 *  和缓存相关的注解
 *      @Cacheable :
 *          会先从缓存中尝试获取对应的数据，如果缓存中获取不到数据，则 查询数据库，并将查询到的结果缓存到redis中
 *          适用于 查询 动作
 *
 *      @CachePut  :  更新缓存
 *          先执行方法、再将方法返回的结果更新到 redis 缓存中
 *
 *      @CacheEvict : 清除缓存
 *          allEntries : 默认值是 false,  是否删除 value 设置的缓存名
 *              如果 allEntries 值为 false, 那么 会删除  缓存名为 value + key 组件的键
 *              如果 allEntries 值为 true, 那么会删除 value 相同的键
 *
 *          beforeInvocation: 默认是 false, 先执行方法，再删除缓存 (推荐)
 *           在 @CacheEvict 注解  #result 只能再 beforeInvocation = false 的时候才能使用
 *
 *      @Caching  : 包含上面三个注解
 *
 *      @EnableCaching  : 启用缓存支持
 *
 *  注解常见的成员：
 *      value / cacheNames :  用来设置缓存的 缓存名(前缀)
 *      key : 用来设置缓存动态名字， 如果设置了key, 且不为空 那么keyGenerator 不在生效
 *           #p0 , #a0 获取方法中第一个参数
 *           #root.methodName : 获取当前的方法名
 *           #root.targetClass : 获取当前类对象名
 *      condition : 条件成立，会进行缓存。默认是条件成立
 *      unless : 条件成立 不进行缓存,  还可以使用 #result 来获取结果，根据结果判断
 */

@Service
@Transactional(rollbackFor = Exception.class)
public class SystemServiceImpl implements SystemService {

    @Resource
    private SysMapper sysMapper ;

    @Resource
    private MenuMapper menuMapper ;


    @Override
    public R<?> saveSys(Sys sys) {
        // 根据系统名，查询系统
        if (sysMapper.findBySysName(sys.getSysName())!=null) {
            return R.fail(R.StatusCode.BAD).data(Map.of("sysName", "系统名已存在"));
        }
        // 如果 系统名不存在，则添加系统到数据库
        int len = sysMapper.insert(sys);

        if (len != 1) throw new ServiceAccessException("数据库插入失败、期待影响 1 行，实际影响" + len + "行") ;

        return R.ok().data(sys);
    }

    @Override
    public R<?> checkSys(String sysName) {
        if (sysMapper.findBySysName(sysName)!=null) {
            return R.fail("系统名已存在").build();
        }
        return R.ok().build();
    }

    @Override
    public R<Sys> queryAllSys() {
        List<Sys> list = sysMapper.findAll();
        return R.<Sys>ok().data(list);
    }

    @Override
    public R<?> updateSys(Sys sys) {
        Sys bySysName = sysMapper.findBySysName(sys.getSysName());

        if (bySysName != null && !Objects.equals(bySysName.getId(), sys.getId())) {
            return R.fail(R.StatusCode.BAD).data(Map.of("sysName", "系统名已存在"));
        }

        int len = sysMapper.updateSys(sys) ;

        if (len != 1) throw new ServiceAccessException("数据库更新失败、期待影响 1 行，实际影响" + len + "行") ;

        return R.ok().data(sys);
    }

    @Override
    public R<?> removeSys(Long id) {
        int len = sysMapper.deleteById(id) ;
        if (len != 1) throw new ServiceAccessException("数据库删除失败、期待影响 1 行，实际影响" + len + "行") ;
        return R.ok().build();
    }

    @Override
    public R<?> removeSys(List<Long> ids) {
        int len = sysMapper.batchDelete(ids) ;
        if (len != ids.size()) throw new ServiceAccessException("数据库删除失败、期待影响 "+ ids.size() +" 行，实际影响" + len + "行") ;
        return R.ok().build();
    }

    @Override
    public R<BindSysMenuDto> queryMenuBindSysList(Long menuId) {
        List<BindSysMenuDto> bindSysByMenuId = menuMapper.findBindSysByMenuId(menuId);
        return R.<BindSysMenuDto>ok().data(bindSysByMenuId);
    }

    @Override
    public R<?> bindMenu(Long sysId, List<Long> menuIds) {
        // 先将 系统 对应的模块全部删除
        int len = sysMapper.removeSysMenuBySysId(sysId) ;

        // 判断 menuIds 是否为空
        if (!menuIds.isEmpty()) {
            sysMapper.batchInsertMenusBySysId(sysId, menuIds);
        }
        return R.ok().build();
    }
}
